<?php

class Util{
   public static function create(){
        return new Util($conn);
    }
    		
    /*
     * CreateGUID is used to return a unique ID to use as an index
     * in the database.  It is a maximum length string of 35.  It uses
     * the PHP command uniqid to create a 23 character string appended
     * to the IP address of the client without periods.                
     * 
     * $return string 
     * */
    
  public static function  createGUID(){
    //Append the IP address w/o periods to the front of the unique ID
    $varGUID = strtoupper(str_replace('.', '', uniqid($_SERVER['REMOTE_ADDR'], TRUE)));
    //add "-"
    // AC041D36-43E8-414E-BD05-F733BCD7298E
    $varGUID = substr($varGUID,0,8).'-'.substr($varGUID,8,4).'-'.substr($varGUID,12,4).'-'.substr($varGUID,16,4).'-'.substr($varGUID,20,12);
    //Return the GUID as the function value
    return $varGUID;
    }
    
    public static  function getDateFromStr($xdateStr, $timestamp = false){
    		//Returns a date string to the default mysql format
    	if($xdateStr==''){
    		//$xdate = mktime(0,0,0,0,0,0);
			//return date("Y-m-d",$xdate);
			return null;
    	}else{
    		if(strpos($xdateStr,'/')>0){
    			if($timestamp){
    				$dateTimeArray = explode(' ',$xdateStr);
    				$xdateStr = $dateTimeArray[0];
    				$timeStr = $dateTimeArray[1];
    			}
	  			$dateArray=explode('/',$xdateStr);
	  			if($timestamp){
	  				$timeArray = explode(':', $timeStr);
	  				if(isset($timeArray[0]))
	  				{
	  					if($timeArray[0]==''){
	  						$dateArray[3] = 0;
	  					}else{
	  						$dateArray[3] = $timeArray[0];	
	  					}
	  					
	  				}
	  				else 
	  				{
	  					$dateArray[3] = 0;
	  				}
	  				if(isset($timeArray[1]))
	  				{
	  					$dateArray[4] = $timeArray[1];
	  				}
	  				else 
	  				{
	  					$dateArray[4] = 0;
	  				}
	  				if(isset($timeArray[2]))
	  				{
	  					$dateArray[5] = $timeArray[2];
	  				}
	  				else 
	  				{
	  					$dateArray[5] = 0;
	  				}
	  			}else{
	  				$dateArray[3] = 0;
	  				$dateArray[4] = 0;
	  				$dateArray[5] = 0;
	  			}
	  			if(count($dateArray)==6){
					$xdate = mktime($dateArray[3],$dateArray[4],$dateArray[5],$dateArray[1],$dateArray[0],$dateArray[2]);
					if($timestamp){
						return date("Y-m-d H:i:s",$xdate);
					}else{
						return date("Y-m-d",$xdate);	
					}
					
	  			}else{
	  				return 	$xdateStr;
	  			}
    		}else{
    			return 	$xdateStr;
    		}
    	}	
    }  
      
    public function getMonths($culture){
		$i18 =  sfContext::getInstance()->getI18N();    	
    	if($culture=='fr'){
    		return array(1=>'Janvier',2=>utf8_encode('F�vrier'),3=>'Mars',4=>'Avril',5=>'Mai',6=>'Juin',7=>'Julliet',8=>utf8_encode('Ao�t'),9=>'Septembre',10=>'Octobre',11=>'Novembre',12=>'Decembre');
    	}elseif($culture=='es'){
    		return array(1=>'Enero',2=>'Febrero',3=>'Marzo',4=>'Abril',5=>'Mayo',6=>'Junio',7=>'Julio',8=>'Agosto',9=>'Septiembre',10=>'Octubre',11=>'Noviembre',12=>'Dicembre');
    	}else{
    		return array(1=>$i18->__('January'),
    					 2=>$i18->__('February'),
    					 3=>$i18->__('March'),
    					 4=>$i18->__('April'),
    					 5=>$i18->__('May'),
    					 6=>$i18->__('Juin'),
    					 7=>$i18->__('July'),
    					 8=>$i18->__('August'),
    					 8=>$i18->__('September'),
    					 10=>$i18->__('October'),
    					 11=>$i18->__('November'),
    					 12=>$i18->__('December'));
       	}
    }
    public function getDaysList($culture){
    	if($culture=='fr'){
    		return array(1 => "Lundi",2 => "Mardi",3 => "Mercredi",4 => "Jeudi",5 => "Vendredi",6 => "Samedi",0 => "Dimanche");
       	}elseif($culture=='es'){
    		return array(1 => "Lunes",2 => "Martes",3 => "Miercoles",4 => "Jueves",5 => "Viernes",6 => "S�bado",0 => "Domingo");
    	}else{
    		return array(1 => "Monday",2 => "Tuesday",3 => "Wednesday",4 => "Thursday",5 => "Friday",6 => "Saturday",0 => "Sunday");
       	}
    }
    
    // Esta funcion acepta como parametro la fecha en formato DD/MM/YYYY
	// 	La funcion regresa el numero correspondiente a la lista siguiente:
	
	// 1 Lunes
	// 2 Martes
	// 3 Miercoles
	// 4 Jueves
	// 5 Viernes
	// 6 Sabado
	// 7 Domingo
	public function weekday($fecha, $format = "d/m/Y"){
	    //$fecha=str_replace("/","-",$fecha);
	    if($format == "d/m/Y"){
	    	list($dia,$mes,$anio)=explode("/",$fecha);	
	    }elseif($format == "m-d-Y"){
	    	list($mes,$dia,$anio)=explode("-",$fecha);
	    }elseif($format == "d-m-Y"){
	    	list($dia,$mes,$anio)=explode("-",$fecha);
	    }elseif($format == "Y-m-d"){
	    	list($anio,$mes,$dia)=explode("-",$fecha);
	    }
	    
	    //return (((mktime ( 0, 0, 0, $mes, $dia, $anio) - mktime ( 0, 0, 0, 7, 17, 2006))/(60*60*24))+700000) % 7;
	    return date("w", mktime(0, 0, 0, $mes, $dia, $anio));
    	
	}
    
	/* compares two timestamps and returns an array with differencies (year, month, day, hour, minute, second)
	 * The difference is in working days.
	 * 
	 * @param date $d1
	 * @param date $d2
	 * 
	 * return array
	*/	
    public static function dateDiff($d1, $d2){

	  //check higher timestamp and switch if neccessary
	  	  $iDate = $d1;//Set the date on this variable to use it to get working days
	  	  $toDate = $d2;
		  if ($d1 < $d2){
		    $temp = $d2;
		    $d2 = $d1;
		    $d1 = $temp;
		  }
		  else {
		    $temp = $d1; //temp can be used for day count if required
		  }
		  $d1 = date_parse(date("Y-m-d H:i:s",$d1));
		  $d2 = date_parse(date("Y-m-d H:i:s",$d2));
		  //seconds
		  if ($d1['second'] >= $d2['second']){
		    $diff['second'] = $d1['second'] - $d2['second'];
		  }
		  else {
		    $d1['minute']--;
		    $diff['second'] = 60-$d2['second']+$d1['second'];
		  }
		  //minutes
		  if ($d1['minute'] >= $d2['minute']){
		    $diff['minute'] = $d1['minute'] - $d2['minute'];
		  }
		  else {
		    $d1['hour']--;
		    $diff['minute'] = 60-$d2['minute']+$d1['minute'];
		  }
		  //hours
		  if ($d1['hour'] >= $d2['hour']){
		    $diff['hour'] = $d1['hour'] - $d2['hour'];
		  }
		  else {
		    $d1['day']--;
		    $diff['hour'] = 24-$d2['hour']+$d1['hour'];
		  }
		  //days
		  if ($d1['day'] >= $d2['day']){
		    $diff['day'] = $d1['day'] - $d2['day'];
		  }
		  else {
		    $d1['month']--;
		    $diff['day'] = date("t",$temp)-$d2['day']+$d1['day'];
		  }
		  //months
		  if ($d1['month'] >= $d2['month']){
		    $diff['month'] = $d1['month'] - $d2['month'];
		  }
		  else {
		    $d1['year']--;
		    $diff['month'] = 12-$d2['month']+$d1['month'];
		  }
		  //years
		  $diff['year'] = $d1['year'] - $d2['year'];
		  //Working day
		  $dif = $toDate - $iDate;
     	  $qDays =  $dif / 60 / 60 / 24; /*Diferencia en d�as*/
     	  $qDays = (int)$qDays;
     	  $diff['fullDay'] = $qDays;
     	  if(sfConfig::get('app_fonctions_workingdays')){
			  $aBankHolidays = self::getHolidays();
			  $holydays = 0;
	    	  for ($i = 1; $i <= $qDays; $i++) {
				if (in_array (date ('w', $iDate),array (0,6) ) || in_array (date ('j_n', $iDate), $aBankHolidays))
				{
					$holydays ++;
				}
				$iDate = strtotime ("+1 day", $iDate);
			  }
			  $diff['workingDay'] = $qDays - $holydays;
     	  }
		  return $diff;    
	}
	
	/*
	 * Retourne un array with the holydays list.
	 * List is contained in a table named holidays.
	 * 
	 */
	public static function getHolidays()
	{
		/* Liste des jours f�ri�s */
		$q = Doctrine_Query::create()->from('holiday h');
		$q->addWhere('h.xyear = ? or h.xyear is null', date('Y'));
		$q->setHydrationMode(Doctrine::HYDRATE_ARRAY);
		$listeFeries = $q->execute();
		foreach ($listeFeries as $holyday){
			$aBankHolidays[] = $holyday['xday'] . '_' . $holyday['xmonth'];
		}
		if (function_exists ('easter_date'))
		{
			$iEaster = easter_date ((int)date('Y'), $iDate);
		}
		else
		{
			$iEaster = getEaster ((int)date('Y'), $iDate);
		}
		$aBankHolidays[] = date ('j_n',$iEaster);
		// Calcul de l'ascension 39 jrs apr�s P�ques
		$aBankHolidays[] = date ('j_n', $iEaster + (86400*39));
		// Calcul du Lundi de la Penc�te 49 jrs apr�s P�ques
		$aBankHolidays[] = date ('j_n', $iEaster + (86400*49));
		return $aBankHolidays;
	} 
	
	public function getYmlDef($fileName){
	  $sf_root_dir = sfConfig::get('sf_root_dir');
	  //echo $sf_root_dir;
	  // Gets the routing file
	  $configFile = $sf_root_dir.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.$fileName ;
	 
	  /* get the route in the routing file */
	  /* first, substract the @ from the route name */
	//  $route = substr($route, 1, strlen($route)) ;
	  if (file_exists($configFile))
		  {
		    $yml = sfYaml::load($configFile) ;
		    return $yml; 
	 		
	      }
	} 
	
	public function getOEDef($classname){
		$array = null;
		try{
			if($classname!=''){
				$regional = sfConfig::get('app_fonctions_autoformsregional', false);
				if($regional){
					$codeRegion = sfContext::getInstance()->getUser()->getCodeRegion();
					$configClassName = $classname.$codeRegion.'config';
					$sf_root_dir = sfConfig::get('sf_root_dir');
					$fileName = $configClassName.'.class.php';
	  				$configFile = $sf_root_dir.DIRECTORY_SEPARATOR.'lib'.DIRECTORY_SEPARATOR.'objectsExtendedDefRegion'.DIRECTORY_SEPARATOR.$fileName ;
	  				if (file_exists($configFile)){
		  				$config = new $configClassName();
			  			$array = $config->configuration;
		  			}
				}
				if(is_null($array)){
		  			$configClassName = $classname.'config';
		  			$sf_root_dir = sfConfig::get('sf_root_dir');
					$fileName = $configClassName.'.class.php';
	  				$configFile = $sf_root_dir.DIRECTORY_SEPARATOR.'lib'.DIRECTORY_SEPARATOR.'objectsExtendedDef'.DIRECTORY_SEPARATOR.$fileName ;
	  				if (file_exists($configFile)){
		  				$config = new $configClassName();
			  			$array = $config->configuration;
		  			}else{
		  				return false;
		  			}
				}
			}else{
				return false;
			}
		}
	
		catch(Doctrine_Exception $e) {
			$ymlDef = $this->getYmlDef('objectsExtendedDef'.DIRECTORY_SEPARATOR.$classname.'.yml');
			if($ymlDef){
				$array = $ymlDef[$classname];
				$this->encodeArray($array);
			}
			$this->sendDebug('Error while creating config class');
		}

		/*$ymlDef = $this->getYmlDef('objectsExtendedDef'.DIRECTORY_SEPARATOR.$classname.'.yml');
		if($ymlDef){
			$array = $ymlDef[$classname];
			$this->encodeArray($array);
		}
		*/
		if(is_array($array)){
			return $array;
		}else{
			return false;
		}
			
	}
	
  	public function getDoctrineTableDef($table){
		$objTable = Doctrine::getTable($table);
		//$objDef = $schema[$table];
		$columns = $objTable->getColumns();
		$columnNames = $objTable->getColumnNames();
		$fieldsNames = $objTable->getFieldNames();
		$myTableDef = array();
		foreach($columnNames as $key => $columnName){
			$myTableDef[$fieldsNames[$key]]=$columns[$columnName];
		}	
		return $myTableDef;
	}
	
	/*Prepares data to bind a doctrine form
	 * 
	 * @param string $table  Table name of the object
	 * $param array $fields 
	 * 
	 * return array
	 * */
	
	public function setFields($table, $fields){
		$columns = $this->getDoctrineTableDef($table);
	  	foreach($columns as $column => $coldef){
	  		/* 
			 * Checkboxes are not sent on post
			 * -------------------------------
			 * There's no way to get browsers send unchecked boxex. 
			 * Better is to know on the server which checkboxes there are, 
			 * so you can deduce that those absent from the posted form values ($_POST in PHP) are unchecked
			 * So we add boolean that are not in the $fields array to be sure that they are setted to false
			 * */
	  		if($coldef['type']=='boolean' and !in_array($column,array_keys($fields))){
	  			$fields[$column]='0';
	  		}
	  		if(in_array($column,array_keys($fields))){
	  			if($coldef['type']=='boolean'){
					if($fields[$column]!=='0' and $fields[$column]!=='1'){
						if($fields[$column] == 'on') $fields[$column]='1';
						if($fields[$column] == 'true') $fields[$column]='1';
						if($fields[$column] == 'off') $fields[$column]='0';
						if($fields[$column] == 'false') $fields[$column]='0';
						if($fields[$column] == '') $fields[$column]='0';
					}
				}elseif($coldef['type']=='integer' or $coldef['type']=='float' or $coldef['type']=='decimal'){
					if(empty($fields[$column])) $fields[$column]=0;
					if(empty($fields[$column])){
						//Si c'est un champ avec relation, il faut faire le mettre � null parce sinon, il cherche la valeur 0 dans la table.
						$relations = Doctrine::getTable($table)->getRelations();
						$relationName = '';
				        foreach ($relations as $name => $relation) {
				        	Util::sendDebug('Nom de la relation!' . $name . 'Local' . $relation->getLocal());
				    		if(strtolower($column)==strtolower($relation->getLocal())){
				    			//unset($fields[$column]);
				    			$fields[$column] = NULL;
				    			//Util::sendDebug('lO METI EN NULL!' . $name);
				    		
				    		}
						}
					}
					  
				}elseif($coldef['type']=='date'){
					/*Est un champ type date, il faut formater la date comme MySQL*/
					if($fields[$column]==''){
						unset($fields[$column]); /// comme ca la date est null
					}else{
						if(strpos($fields[$column],'/')>0){
							$fields[$column] = $this->getDateFromStr($fields[$column]);
						}
					}			
				}
				elseif($coldef['type']=='timestamp'){
					$fields[$column] = $this->getDateFromStr($fields[$column], true);
				}
	  		}
		}
		return $fields;  	
	}

	/* Returns the navigation buttons for the pager object.
	 * 
	 * @param sfDoctrinePager $pager  
	 * @param string $orderCol 
	 * 
	 * return string
	 * */
		
	public static function pager_navigation($pager, $orderCol)
	{
		$navigation = ''; 
		if ($pager->haveToPaginate())
		{ 
			// First and previous page
			if ($pager->getPage() != 1)
			{
				$navigation .= '<a href="javascript:refresh(1,\''.$orderCol.'\');"><img align="absmiddle" src="/images/icons/first.png" title="Refresh"/></a>';
				$navigation .= '<a href="javascript:refresh('.$pager->getPreviousPage().',\''.$orderCol.'\');"><img align="absmiddle" src="/images/icons/previous.png" title="Refresh"/></a>';
		    }
		 
		    // Pages one by one
			$links = array();
		    
			foreach($pager->getLinks() as $page)
		    {
		    	if($page == $pager->getPage()){
		    		$links[] = $page;
		    	}else{
		    		$links[] = '<a href="javascript:refresh('.$page.',\''.$orderCol.'\');">'.$page.'</a>';
		    	}
		    }
		    
		    $navigation .= join('  ', $links);
		 
		    // Next and last page
		    if($pager->getPage() != $pager->getLastPage())
		    {
				$navigation .= '<a href="javascript:refresh('.$pager->getNextPage().',\''.$orderCol.'\');"><img align="absmiddle" src="/images/icons/next.png" title="Refresh"/></a>';
		    	$navigation .= '<a href="javascript:refresh('.$pager->getLastPage().',\''.$orderCol.'\');"><img align="absmiddle" src="/images/icons/last.png" title="Refresh"/></a>';
		    }
		}
		return $navigation;
	}     
  
	
	function getCharset(){
		$charset = 'utf8';
		$settings = $this->getYmlDef('/settings.yml');
		if($settings){
			if(in_array('all',array_keys($settings))){
				$all = $settings['all'];
				if(in_array('.settings',array_keys($all))){
					$sett = $all['.settings'];
					if(in_array('charset',array_keys($sett))){
							$charset = $sett['charset'];
					}
				}
			}	
		}
		return $charset;
	}
	
	
	public function encodeArray(&$array){
		foreach($array as $key=>$value){
			if(is_array($value)){
				$this->encodeArray($value);
				$array[$key]=$value;
			}else{
				$array[$key]=utf8_encode($value);
			}
		}		
		return $array;
	}
		
    public function getTableDef($table){
	    $yml = $this->getYmlDef('doctrine/schema.yml') ;
	    //print_r($yml);
		$columns = $yml[$table]['columns'];
		return $columns;
    }
    
    
	/**
	* Returns a filename based on the $name paramater that has been
	* striped of special characters, it's spaces changed to underscores,
	* and shortened to 50 characters... but keeping it's extension
	* PD: Updated to keep extensions, based on code by timdw at
	* <a href="http://forums.codecharge.com/posts.php?post_id=75694
	" title="http://forums.codecharge.com/posts.php?post_id=75694
	" rel="nofollow">http://forums.codecharge.com/posts.php?post_id=75694
	</a> */
	public static function sanitize_filename($name) {
	  $special_chars = array ("#","$","%","^","&","*","!","~","�","\"","�","'","=","?","/","[","]","(",")","|","<",">",";","\\",",",".");
	  $name = preg_replace("/^[.]*/","",$name); // remove leading dots
	  $name = preg_replace("/[.]*$/","",$name); // remove trailing dots
	 
	  $lastdotpos=strrpos($name, "."); // save last dot position
	 
	  $name = str_replace($special_chars, "", $name);  // remove special characters
	 
	  $name = str_replace(' ','_',$name); // replace spaces with _
	  $name = str_replace("'", "", $name);
	  $afterdot = "";
	  if ($lastdotpos !== false) { // Split into name and extension, if any.
	    if ($lastdotpos < (strlen($name) - 1))
	        $afterdot = substr($name, $lastdotpos);
	   
	    $extensionlen = strlen($afterdot);
	   
	    if ($lastdotpos < (50 - $extensionlen) )
	        $beforedot = substr($name, 0, $lastdotpos);
	    else
	        $beforedot = substr($name, 0, (50 - $extensionlen));
	  }
	  else   // no extension
	   $beforedot = substr($name,0,50);
	
	 
	  if ($afterdot)
	    $name = $beforedot . "." . $afterdot;
	  else
	    $name = $beforedot;
	 
	  return $name;
	
	}
	
	public static function getOptions($table, $colId, $colName, $filter, $addEmpty, $isnumeric = false){
   		$q=Doctrine_Query::create()
	    					->select('a.'.$colId.' as id, a.'.$colName.'  as name')
						    ->from($table.' a') 
						    ->orderBy('a.'.$colName);
		 if(!$filter==''){
		 	if(substr($filter, 0,1) != '(')
		 	{
		 		$filter = 'a.'.$filter;
		 	}
		 	$q->andWhere($filter);
		 }
		 $q->setHydrationMode(Doctrine_Core::HYDRATE_ARRAY); 
		 $options= $q->execute();
		 $val=array();
		 if($addEmpty){
		 	if($isnumeric){
		 		//$this->getContext()->getI18N()->__($text, $args, 'messages');
		 		$val['0'] = sfContext::getInstance()->getI18N()->__('Please select a value...');
		 	}else{
		 		$val[''] = sfContext::getInstance()->getI18N()->__('Please select a value...');	
		 	}
		 }
	  	 foreach($options as $opt){
		 	$val[$opt['id']]=$opt['name'];
		 }
		 return $val;
   }
   
   
   /*
    * Process a default value to see if it's an expression. If its an expression, returns the corresponding value
    * Expressions :
    * 	-currentDate
    * 	-currentHour
    *   -lastYear
    *   -nextYear
    *   -firstDayOfMonth
    *   -firstDayOfYear
    * 	-blank
    * 	-linkedUser  =>user profile id linked to sfUser
    *   -userName	 => sfUser->getUserName()
    * 
    * @param variant $value
    * @param string  $datatype
    * @param dateFormat | Only for date or timestamp 
    * 
    * @return string
    * */
   
   public static function processDefaultExpression($value, $datatype, $dateFormat = 'd/m/Y' )
   {
   		if($datatype=='boolean'){
			if(strtoupper($value)=='true' or strtoupper($value)==1 or strtoupper($value)=='on'){
				return true;
			}else{
				return false;
			}
		}
   		if($value=='currentDate')
   		{
			if($datatype=='timestamp' or $datatype=='datetime'){
				 return date("$dateFormat  H:i:s");
			}else{
				 return date($dateFormat);
			}
		}
		elseif($value=='currentHour')
		{
			return date("H:i");
		}
   		elseif($value=='currentYear')
		{
			return date("Y");
		}
   		elseif($value=='lastYear')
		{
			return date("Y") - 1;
		}
   		elseif($value=='nextYear')
		{
			return date("Y") + 1;
		}
		elseif($value=='blank')
		{
			return "";
		}
		elseif($value=='linkedUser')
		{
			$user =  sfContext::getInstance()->getUser()->getUserProfile();
			if($user){
				return $user['id'];
			}
		}elseif($value=='firstDayOfMonth'){
	    	$year = date('Y');
	    	$month = date('m');
	    	$day = 1;
	    	return date("d/m/Y",mktime(0,0,0,$month,$day,$year));
		}elseif($value=='firstDayOfYear'){
	    	$year = date('Y');
	    	$month = 1;
	    	$day = 1;
	    	return date("d/m/Y",mktime(0,0,0,$month,$day,$year));
		}elseif($value=='lastDayOfYear'){
	    	$year = date('Y');
	    	$month = 12;
	    	$day = 31;
	    	return date("d/m/Y",mktime(0,0,0,$month,$day,$year));
		}		
		elseif($value=='userName')
		{
			$userName =  sfContext::getInstance()->getUser()->getUserName();
			return $userName;
	    }else
	    {
			return $value;
		}			
   }
   
   public static function getArrayFromStr($string, $itemsSeparator, $emptyValue=false, $keysSeparator = '=>'){
   		if($emptyValue){
   			if(is_string($emptyValue)){
   				$options = array(''=>$emptyValue);
   			}else{
   				$options = array(''=>sfContext::getInstance()->getI18N()->__('Please select a value...'));
   			}
   		}else{
   			$options = array();
   		}
   		if($string==''){
   			return $options;
   		}
   		//$strOptions = str_replace(' ', '',$string);
   		$strOptions = utf8_encode(html_entity_decode($string));
		if(strpos($strOptions, $keysSeparator) !== false) { //Keys and Values
			$array = explode($itemsSeparator,$strOptions);
			foreach($array as $val){
				$array2 = explode($keysSeparator,$val);
				if(count($array2)==2)
					$options[trim($array2[0])]=trim($array2[1]);
			}
		}else{ //Only Values
			//$options = explode(';',$strOptions);
			$strOptions = utf8_encode(html_entity_decode($string));
			$options = array_merge($options,explode($itemsSeparator,$strOptions));
		}
		return $options;
   }
   
   //adds totals to an array
   
  public static function addSubTotalsToArray($def , $data, $fullRowTotal = true, $fullColumnTotal = true){
		
		$subtotals = array();//This array will keep the subtotals
		$elemCount=array();//This array will keep the amount of elements of each category. Usefull for media calculation!
	    foreach($def as $columnName => $rowConfig){
	    	if($rowConfig['hasTotals']){
				$subtotals[$columnName] =array();
    			$elemCount[$columnName] =array();	    		
	    	}
	    }
	    
	    /*First loop to add values and insert data into totals arrays*/
		$columnTotalArray = array();//These arrays will store the column total values to add the full total line at the end
		$columnCountArray = array();
	    foreach ($data as $row) {
	        $rowValues = array();//This array wil have all the row values.
	        $rowTotalArray = array();
			$rowCountArray = array();
	        foreach($row as $columnName => $value) {
	        	if(array_key_exists($columnName,$subtotals)){//This column has totals
	        		//$subtotals[$columnName][$value]=array();
	        		//$subtotals[$columnName][$value][$columnName]='Total: '.$value;
	        	}else{
	        		/*If its a value, I add to each subtotal on the due column*/
	        		if($def[$columnName]['t_function']!=''){
	        			//if($def[$columnName]['t_function']=='sum'){
	        				foreach( array_keys($subtotals) as $sTotalKey){
	        					if(is_numeric($value)){
		        					$subtotals[$sTotalKey][$row[$sTotalKey]][$columnName] += $value;
		        					$elemCount[$sTotalKey][$row[$sTotalKey]][$columnName] += 1;
		        					$rowTotalArray[$sTotalKey][$row[$sTotalKey]] +=$value;
		        					$rowCountArray[$sTotalKey][$row[$sTotalKey]] +=1;
	        					}
	        				}
	        			//}
        				if(is_numeric($value)){
	        				$columnTotalArray[$columnName] += $value;
		        			$columnCountArray[$columnName] += 1;
        				}
	        		}
	        		
	        	}
	        }
	    }

	    /*Second loop to mix the data with the totals.*/
		$newData = array();
		$arrayControl = array();/*This array will hold the cut control values*/
		foreach ($data as $row) {
			$addTotal = null;
			$rowTotal = 0;
			$rowCount = 0;
			foreach($row as $columnName => $value) {
				if(array_key_exists($columnName,$subtotals)){//This column has totals
	        		if(array_key_exists($columnName,$arrayControl)){//It means the value of this column changed, we have to show a total line
	        			if($arrayControl[$columnName]!=$value){//
	        				//We must add the total line!
	        				$addTotal[] = $columnName;
	        				$newTotalValue[$columnName] = $value;
	        			}
	        		}else{
	        			$arrayControl[$columnName] = $value;//It's the first time, we add it to the control array.
	        		}
	        	}
			}
			
			if(!is_null($addTotal)){
				foreach(array_reverse($addTotal) as $TotalColumnName){ //I use array_reverse to add the inner totals first.
					$sTotalLine = null;
					foreach($row as $columnName => $value) {
						if($columnName==$TotalColumnName){
							/*Its the column we are totalizing*/
							$totalValue = $arrayControl[$columnName];
							$totalRow[$columnName] = 'Total '.$totalValue;
							$sTotalLine = array();
							foreach($subtotals[$columnName][$totalValue] as $totalCol => $valueTot){
								/*if($this->_totalFunction=='AVG'){
									$sTotalLine[$totalCol]=$valueTot/$elemCount[$columnName][$totalValue][$totalCol];
								}else{
									$sTotalLine[$totalCol]=$valueTot;
								}*/
								//$sTotalLine[$totalCol]=$valueTot;
									if($def[$totalCol]['t_function']!=''){
					        			if($def[$totalCol]['t_function']=='sum'){
					        				$sTotalLine[$totalCol]=$valueTot;
					        			}elseif($def[$totalCol]['t_function']=='avg'){
					        				$sTotalLine[$totalCol]=$valueTot/$elemCount[$columnName][$totalValue][$totalCol];
					        			}else{
					        				if(substr($def[$totalCol]['t_function'], 0, 1) == '='){
					        					//It's a calculated total
					        					//$sTotalLine[$totalCol] = 0.03;
					        					$sTotalLine[$totalCol] = self::getFormulaResult($def[$totalCol]['t_function'], array_keys($def), $sTotalLine);
					        				}else{
					        					$sTotalLine[$totalCol]=$valueTot;	
					        				}
					        				
					        			}
									}else{
										$totalRow[$columnName] = '';/*It's a non value column, I add a white space*/
									}
								
							}
							$arrayControl[$columnName] = $newTotalValue[$columnName];
						}else{
							if(!is_null($sTotalLine)){
								if(array_key_exists($columnName,$sTotalLine)){
									$totalRow[$columnName] = $sTotalLine[$columnName];	
								}else{
									$totalRow[$columnName] = '';
								}
							}else{
								if(array_key_exists($columnName,$arrayControl)){
									//It's column with totals, we have to get the old value.
									$totalRow[$columnName] = $arrayControl[$columnName];
								}else{
									$totalRow[$columnName] = $value;
								}
							}
						}
					}
					$newData['Total'.'_'.$TotalColumnName.$totalValue]=$totalRow;					
				}
			}
			$newData[]=$row;
		}
		if(count($data)>0){
			/*It's the last row, we have to add a total for each column with subtotal*/
			$row = $data[count($data)-1];
			$addTotal = null;
			$rowTotal = 0;
			$rowCount = 0;
			foreach($row as $columnName => $value) {
				if(array_key_exists($columnName,$subtotals)){//This column has totals
	        		if(array_key_exists($columnName,$arrayControl)){//It means the value of this column changed, we have to show a total line
	        			//We must add the total line!
	        			$addTotal[] = $columnName;
	        			$newTotalValue[$columnName] = $value;
	        		}
	        	}else{
	        		if($def[$columnName]['t_function']!=''){
	        			if($def[$columnName]['t_function']!='sum'){
		        			if(trim($value)!==''){	        			
		        				$rowTotal += $value;
		        				$rowCount += 1;
							}
	        			}
	        		}
	        	}
			}
			
			if(!is_null($addTotal)){
					foreach(array_reverse($addTotal) as $TotalColumnName){ //I use array_reverse to add the inner totals first.
						$sTotalLine = null;
						foreach($row as $columnName => $value) {
							if($columnName==$TotalColumnName){
								/*Its the column we are totalizing*/
								$totalValue = $arrayControl[$columnName];
								$totalRow[$columnName] = 'Total '.$totalValue;
								$sTotalLine = array();
								foreach($subtotals[$columnName][$totalValue] as $totalCol => $valueTot){
									if($def[$totalCol]['t_function']!=''){
					        			if($def[$totalCol]['t_function']=='sum'){
					        				$sTotalLine[$totalCol]=$valueTot;
					        			}elseif($def[$totalCol]['t_function']=='avg'){
					        				$sTotalLine[$totalCol]=$valueTot/$elemCount[$columnName][$totalValue][$totalCol];
					        			}else{
					        				if(substr($def[$totalCol]['t_function'], 0, 1) == '='){
					        					//It's a calculated total
					        					//$sTotalLine[$totalCol] = 0.03;
					        					$sTotalLine[$totalCol] = self::getFormulaResult($def[$totalCol]['t_function'], array_keys($def), $sTotalLine);
					        				}else{
					        					$sTotalLine[$totalCol]=$valueTot;	
					        				}
					        				
					        			}
									}else{
										$totalRow[$columnName] = '';/*It's a non value column, I add a white space*/
									}
								}
								$arrayControl[$columnName] = $newTotalValue[$columnName];
							}else{
								if(!is_null($sTotalLine)){
									if(array_key_exists($columnName,$sTotalLine)){
										$totalRow[$columnName] = $sTotalLine[$columnName];	
									}else{
										$totalRow[$columnName] = '';
									}
								}else{
									if(array_key_exists($columnName,$arrayControl)){
										//It's column with totals, we have to get the old value.
										$totalRow[$columnName] = $arrayControl[$columnName];
									}else{
										$totalRow[$columnName] = $value;
									}
								}
							}
						}
						$newData['Total'.'_'.$TotalColumnName.$totalValue]=$totalRow;					
					}
			}
			
			if($fullRowTotal){
				//Add the full total line
				$row = $data[count($data)-1];
				$first = true;
				$totalRow = array();
				foreach($row as $columnName => $value) {
					if($columnName=='_id'){
						$totalRow[$columnName]=count($newData);
					}else{
						if($first){
							$totalRow[$columnName] = 'Total';//self::TOTAL;
							$first = false;	
						}else{
							if($def[$columnName]['t_function']!=''){
			        			if($def[$columnName]['t_function']=='sum'){
			        				$totalRow[$columnName] = $columnTotalArray[$columnName];
			        			}elseif($def[$columnName]['t_function']=='avg'){
			        				$totalRow[$columnName] = $columnTotalArray[$columnName] / $columnCountArray[$columnName];
			        			}else{
			        				if(substr($def[$columnName]['t_function'], 0, 1) == '='){
			        					//It's a calculated total
			        					$totalRow[$columnName] = self::getFormulaResult($def[$columnName]['t_function'], array_keys($def), $columnTotalArray);
			        				}else{
			        					$totalRow[$columnName] = $columnTotalArray[$columnName];	
			        				}
			        				
			        			}
							}else{
								$totalRow[$columnName] = '';/*It's a non value column, I add a white space*/
							}
						}
					}
				}
				$newData['Total']=$totalRow;
			}
		}
	    return $newData;
   	
   	
   		
   }
   
   
   public static function getFormulaResult($formula, $columDefs, $columnTotals){
   		$formula = str_replace('=', '', $formula);
		foreach($columDefs as $columnName){
			if($columnTotals[$columnName]==''){
				$value = 0;
			}else{
				$value = $columnTotals[$columnName];
			}
			$formula = str_replace('{'.$columnName.'}', $value, $formula);
		}
		if(is_callable('return ' . $formula . ';')){
			$calculFunction = create_function('', 'return ' . $formula . ';');
		}else{
			$calculFunction = create_function('', 'return 0;');
		}
		return $calculFunction();			        					
   	
   }
   
   public function getDoctrineDef($classname, $fieldName, $doctrineColumns = false){
		$objTable = Doctrine::getTable($classname);
   		if(!$doctrineColumns)
   		{
			$doctrineColumns = $objTable->getColumns();
	   	}
		$typeDoct = 'string';
		$relatedClass = '';	   	
	   	if(isset( $doctrineColumns[strtolower($fieldName)])){
	   		$attDoct = $doctrineColumns[strtolower($fieldName)];
			if(in_array('type',array_keys($attDoct))){
					$typeDoct = $attDoct['type'];
			}
			$relations = $objTable->getRelations();
			foreach ($relations as $name => $relation) {
	   			if($fieldName==$relation->getLocal()){
	    				$typeDoct='BO';
	    				$relatedClass = $relation->getClass();
	   			}
			}
	   	}
		unset($objTable);
		unset($attDoct);
		return array('type'=>$typeDoct,'relatedClass'=>$relatedClass);
   }
   
   
  /* Returns field name that makes the link with the parent table in a pere-child relationship.
   * The function searchs all one to one relations of the current object, 
   * and for each related object, searchs a one to many relation reflecting to him
   * 
   * @param string $att_type 	|whether to search for List or BoList (default BOList) 
   * 
   * return string
   * 
   * */
  public static function getOwnerFieldAndClass($object, $att_type = 'BOList')
  {
  		$relations = $object->getTable()->getRelations();	
	  	$class = $object->getTable()->getClassnameToReturn();
  		foreach ($relations as $name => $relation) 
		{
		    //Util::sendDebug('Relation!:' . $name);
	      	if($relation->getType() == 0)
	       	{
				$relatedClass = $relation->getClass();
				$relatedObjDef = new objectDef($relatedClass);
				if($relatedObjDef->classExists)
				{
					$relationsPere = Doctrine::getTable($relatedClass)->getRelations();
					foreach ($relationsPere as $namePere => $relationPere) 
		    		{
		    			if(isset($relatedObjDef->attributes[$namePere]))
		    			{
			    			//Util::sendDebug('Relation 2!:' . $namePere . '-' . $relationPere->getForeign());
			    			if($relationPere->getType() == 1 and $relatedObjDef->attributes[$namePere]['type']==$att_type)
			    			{
			    				//Util::sendDebug('$relation->getClass()!:' . $relationPere->getClass());
			    				if($class == $relationPere->getClass())
			    				{
			    					//Util::sendDebug('Fin Relation Finder');
			    					return array('ownerField' => $relation->getLocal(), 'ownerClass' => $relation->getClass());
			    				}
			    					
			    			}
		    			}
		    			
		    		}
				}
	    	}
		}
		return false;
  }
   
	public function sendPhpMail($to, $from, $subject, $body, $reply_to = '' ){
	 /*	$Destinataire="andreslartigue@gmail.com"; 
		$Expediteur     = "IEEN_SRV_Applicatifs"; 
		$Objet          = "IEEN SRV : Test envoi Mail F"; 
		$Reponse        = "egs-toulouse-ai@erdf-grdf.fr"; */
	                                
		if($reply_to == ''){
			$reply_to = $from;
		}
		$prefij = '['.sfConfig::get('app_mails_subjectDefault', '').']';
		
		$objet = $prefij.$subject;
		$msg .= $body; 
		$envMails = sfConfig::get('app_mails_mailsActive', true);
		if($envMails){
			$Result = mail($to, utf8_encode($subject), $body, "From: $from \nReply-to: $reponse Content-type: text/html\r\n");
		}else{
			$Result = false;
		}
		
		 
		return $Result;
	 }
	 		
	 public function sendSwiftMail($arrayTo, $nameFrom, $mailFrom , $subject, $body, $attach = ''){
	
		  $mailValide = true;
		  foreach($arrayTo as $mailAddress){
		  	if($mailAddress=='') $mailValide = false;
		  }
		  if($mailValide){
		  	
		  //Create the message
		  $message = Swift_Message::newInstance()
		
		  //Give the message a subject
		  ->setSubject(utf8_encode($subject))
		  ->setFrom(array($mailFrom => utf8_encode($nameFrom)))
		
		  //Set the To addresses with an associative array
		  //->setTo(array('andres.lartigue@gmail.com', 'andres.lartigue@gmail.com' => 'Andres Lartigue'))
		  ->setTo($arrayTo)
		  //Give it a body
		  ->setBody(utf8_encode($body), 'text/html')
		
		  //And optionally an alternative body
		  //->addPart('<q>Here is the message itself</q>', 'text/html')
		
		  //Optionally add any attachments
		 // ->attach(Swift_Attachment::fromPath('my-document.pdf'))
		  ;
		  if($attach!=''){
		  	 $message->attach(Swift_Attachment::fromPath($attach));
		  }
		  //Create the Transport
		  $mailServer = sfConfig::get('app_mails_mailserver', '');
		  if($mailServer!=''){
		  		$user = sfConfig::get('app_mails_user', '');
		  		$password = sfConfig::get('app_mails_password', '');
		  		$port = sfConfig::get('app_mails_port', 25);
			  	$transport = Swift_SmtpTransport::newInstance($mailServer, $port)
		  		->setUsername($user)
		  		->setPassword($password);
		  }else{
		  	$transport = Swift_MailTransport::newInstance();
		  }
		
			//You could alternatively use a different transport such as Sendmail or Mail:
			//Sendmail
			//$transport = Swift_SendmailTransport::newInstance('/usr/sbin/sendmail -bs');
		
			//Mail
			
			//Create the Mailer using your created Transport
			$mailer = Swift_Mailer::newInstance($transport);
			
			//Send the message
			$envMails = sfConfig::get('app_mails_mailsActive');
			if($envMails){
				$result = $mailer->send($message);	
			}else{
				$result = false;	
			}
		  //Set the From address with an associative array
		  
		  }else{
		  	$result = false;
		  }
		return $result;  
	/*
	You can alternatively use batchSend() to send the message
	
	$result = $mailer->batchSend($message);
	*/
	  
	// Create the mailer and message objects
	/*  $mailer = new Swift(new Swift_Connection_NativeMail());
	  $message = new Swift_Message('Mail\'s subject', $mailBody, 'text/html');
	  $mailTo = 'andres.lartigue@gmail.com';
	  $mailFrom = 'alartigue@binova.com.ar';*/
	  // Send
	/*  $mailer->send($message, $mailTo, $mailFrom);
	  $mailer->disconnect();
	 */	
	 }   
	 
	 public function setExtraAttributes($form){
		foreach($_SESSION['extraAttributes'] as $fieldName => $array){
    		foreach($array as $key => $value){
    			if($key=='label'){
    				$form->offsetGet($fieldName)->getWidget()->setLabel($value);
    			}elseif($key=='attributes'){
    				$form->offsetGet($fieldName)->getWidget()->setAttributes($value);	
    			}
    			
    		}
    	}
	 }
	   
   	public static function stripAccents($string)
	{
		return strtr($string,'���������������������������������������������������','aaaaaceeeeiiiinooooouuuuyyAAAAACEEEEIIIINOOOOOUUUUY');
	}
	
	public static function stripAccents2($string, $htmlCodes = false)
	{
		if($htmlCodes){
			$caract = array("&aacute;", "&agrave;", "&acirc;", "&eacute;", "&egrave;", "&ecirc;", "&iacute;", "&igrave;", "&icirc;", "&oacute;", "&ograve;", "&ocirc;", "&uacute;", "&ugrave;", "&ucirc;", "&deg;", "&Aacute;", "&Agrave;", "&Acirc;", "&Eacute;", "&Egrave;", "&Ecirc;", "&Iacute;", "&Igrave;", "&Icirc;", "&Oacute;", "&Ograve;", "&Ocirc;", "&Uacute;", "&Ugrave;", "&Ucirc;", "&ccedil;", "&Ccedil;","&iquest;");	
		}else{
			$caract = array("�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�",  "�", "�", "�", "�", "�", "�", "�", "�",'�');	
		}
		$sansAccent = array("a", "a", "a", "e", "e", "e", "i", "i", "i", "o", "o", "o", "u", "u", "_", "A", "A", "A", "A", "E", "E", "E", "I", "I", "I",  "I", "I", "I", "I", "I", "I", "c", "C","_");
		$string = str_replace($caract, $sansAccent, $string);
		return $string; 
	}
	
	/*Saves object as array
	 *  @param string $classname  |Classname of the object to be saved.
	 *  @param string $descriptor |A string that describes the object
	 *  @param variant $data 		|an object or an array with the object representation 
	 * 
	 *  return draft
	 * */
	
	public static function saveDaft($classname, $descriptor, $data){
		$draft = new draft();
		$draft->object_class = $classname;
		$draft->descriptor = $descriptor;

		$draft->object_data = serialize($data);
		$draft->user_id = sfContext::getInstance()->getUser()->getUserProfile()->id;	
		$draft->save();
		return $draft;
	}
	
	public static function getDrafts($sfUser = null){
		if(is_null($sfUser)){
			 sfContext::getInstance()->getUser()->getUserProfile();
		}
		$user = $sfUser->getUserProfile();
		$q = Doctrine_Query::create()->from('draft')
			->addWhere('user_id = ?', $user->id);
		$q->setHydrationMode(Doctrine::HYDRATE_ARRAY);
		return $q->execute();			
	}
	
	public static function stripCaract($string)
	{
		$caract = array("&aacute;", "&agrave;", "&acirc;", "&eacute;", "&egrave;", "&ecirc;", "&iacute;", "&igrave;", "&icirc;", "&oacute;", "&ograve;", "&ocirc;", "&uacute;", "&ugrave;", "&ucirc;", "&deg;", "&Aacute;", "&Agrave;", "&Acirc;", "&Eacute;", "&Egrave;", "&Ecirc;", "&Iacute;", "&Igrave;", "&Icirc;", "&Oacute;", "&Ograve;", "&Ocirc;", "&Uacute;", "&Ugrave;", "&Ucirc;", "&ccedil;", "&Ccedil;", "&iquest;");
		$alpha = array("�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�", "�",  "�", "�", "�", "�", "�", "�", "�", "�",'�');
		
		$alpha_encode = array();
		foreach($alpha as $element)
		{
		    $alpha_encode[] = utf8_encode($element);
		}
		
		$string = str_replace($caract, $alpha_encode, $string);
		return $string; 
	}
	
	/*
	 * Sends a string to symfony log
	 * 
	 * @param string $string   
	 * @param integer $level   |1=normal, 2=warning, 3=>error
	 * 
	 * */
	
	public static function sendDebug($string, $level = 1){
		if($level==2)
		{
			$string = 'Warning: ' . $string;
		}elseif($level==3){
			$string = 'Error: ' . $string;
		}
	 	sfContext::getInstance()->getLogger()->debug($string);
	}
	
	public static function sendDebugArray($array){
		foreach($array as $key=>$value){
			if(is_array($value)){
				$this->sendDebugArray($value);
			}else{
	 			sfContext::getInstance()->getLogger()->debug("$key => $value");
			}
		}
	}
	
}

/*
 * This is a simple short-hand wrapper for Doctrine_Query. It provides
 * a shorter class name and a few additional functions.
 */
class DQ extends Doctrine_Query
{
	/**
	 * Returns a DQ object to get started
	 *
	 * @return DQ
	 */
    public static function create($conn = null, $class = null)
    {
        /*if ( ! $class) {
            $class = Doctrine_Manager::getInstance()
                ->getAttribute(Doctrine_Core::ATTR_QUERY_CLASS);
        }*/
        return new DQ($conn);
    }
	/**
	 * This function will wrap the current dql where statement
	 * in parenthesis. This allows more complex dql statements
	 * It can be called multiple times during the creation of the dql
	 * where clause.
	 *
	 * @return $this
	 */
	public function whereParenWrap() {
		$where = $this->_dqlParts['where'];
		if (count($where) > 0) {
			array_unshift($where, '(');
			array_push($where, ')');
			$this->_dqlParts['where'] = $where;
		}

		return $this;
	}            

	public function whereOpenParen() {
		$where = $this->_dqlParts['where'];
		if (count($where) > 0) {
			array_push($where, 'and (');
			$this->_dqlParts['where'] = $where;
		}

		return $this;
	}   
	
	public function andWhereOpenParen($where, $params = array())
    {
        if (is_array($params)) {
            $this->_params['where'] = array_merge($this->_params['where'], $params);
        } else {
            $this->_params['where'][] = $params;
        }

        if ($this->_hasDqlQueryPart('where')) {
            $this->_addDqlQueryPart('where', 'AND (', true);
        }

        return $this->_addDqlQueryPart('where', $where, true);
    }

	public function orWhereOpenParen($where, $params = array())
    {
        if (is_array($params)) {
            $this->_params['where'] = array_merge($this->_params['where'], $params);
        } else {
            $this->_params['where'][] = $params;
        }

        if ($this->_hasDqlQueryPart('where')) {
            $this->_addDqlQueryPart('where', 'OR (', true);
        }

        return $this->_addDqlQueryPart('where', $where, true);
    }
        
	public function whereCloseParen() {
		$where = $this->_dqlParts['where'];
		if (count($where) > 0) {
			array_push($where, ')');
			$this->_dqlParts['where'] = $where;
		}

		return $this;
	}   
	
	/**
	 * Create and andWhere if the where parameter is not empty
	 *
	 * @param string $where where string
	 * @param parameters $params
	 *
	 * @return DQ this object
	 */
	public function andWhereIf($where, $params = array()) {
		return empty($where)
			? $this
			: $this->andWhere($where, $params);
	}

	/**
	 * Create and orWhere if the where parameter is not empty
	 *
	 * @param string $where where string
	 * @param parameters $params
	 *
	 * @return DQ this object
	 */
	public function orWhereIf($where, $params = array()) {
		return empty($where)
			? $this
			: $this->orWhere($where, $params);
	}

}
